# +----------------------------------------------------------------------
# | ChatWork智能聊天办公系统
# +----------------------------------------------------------------------
# | 软件声明: 本系统并非自由软件,未经授权任何形式的商业使用均属非法。
# | 版权保护: 任何企业和个人不允许对程序代码以任何形式任何目的复制/分发。
# | 授权要求: 如有商业使用需求,请务必先与版权所有者取得联系并获得正式授权。
# +----------------------------------------------------------------------
# | Author: ChatWork Team <2474369941@qq.com>
# +----------------------------------------------------------------------
from exception import AppException
from common.enums.pay import PayEnum
from common.utils.urls import UrlUtil
from common.models.dev import DevPayConfigModel
from common.models.market import RechargeOrderModel
from common.models.market import SubscribeOrderModel
from plugins.paid.wxpay import WxpayService
from plugins.paid.ailpay import AlipayService
from apps.api.schemas import payment_schema as schema


class PaymentService:
    """ 支付服务类 """

    @classmethod
    async def pay_way(cls):
        """
        支付方式

        Author:
            zero
        """
        ways = await DevPayConfigModel.filter(status=1).order_by("-sort", "-id").all()
        _data = []
        for item in ways:
            _data.append(schema.PayWayListVo(
                channel=item.channel,
                shorter=item.shorter,
                icon=await UrlUtil.to_absolute_url(item.icon)
            ))
        return _data

    @classmethod
    async def listen(cls, attach: str, order_id: int, user_id: int) -> schema.PayListenVo:
        """
        订单监听

        Args:
            attach (str): 场景: [recharge, subscribe]
            order_id (int): 订单ID
            user_id (int): 用户ID

        Author:
            zero
        """
        # 查询订单
        order = None
        if attach == "recharge":
            order = (await RechargeOrderModel
                     .filter(id=order_id, user_id=user_id)
                     .first()
                     .values("id", "pay_status"))
        elif attach == "subscribe":
            order = (await SubscribeOrderModel
                     .filter(id=order_id, user_id=user_id)
                     .first()
                     .values("id", "pay_status"))

        # 状态定义: [-1=订单不存在, 0=未支付, 1=已支付, 2=已过期]
        data = schema.PayListenVo(status=0, message="订单未支付")

        # 订单丢失
        if not order:
            data.status = -1
            data.message = "订单异常"

        # 支付成功
        if order["pay_status"] == PayEnum.PAID_OK:
            data.status = 1
            data.message = "订单已支付"

        return data

    @classmethod
    async def prepay(cls, terminal: int, post: schema.PayPrepayIn):
        """
        预支付下单

        Args:
             terminal (int): 来源终端
             post (schema.PayPrepayIn): 支付参数

        Author:
            zero
        """
        order = None
        description: str = ""
        if post.attach == "recharge":
            description = "充值余额"
            order = await RechargeOrderModel.filter(id=post.order_id).first()
        elif post.attach == "subscribe":
            description = "订阅套餐"
            order = await SubscribeOrderModel.filter(id=post.order_id).first()

        if not order:
            raise AppException("订单不存在")

        # 更新支付方式
        order.pay_pay = post.pay_way
        order.terminal = terminal
        await order.save()

        # 发起支付请求
        try:
            if post.pay_way == PayEnum.WAY_MNP:
                return await WxpayService.unify_order(terminal, post.attach, {
                    "out_trade_no": order.order_sn,
                    "order_amount": order.paid_amount,
                    "description": description,
                    "redirect_url": post.redirect_url
                })
            elif post.pay_way == PayEnum.WAY_ALI:
                return await AlipayService.unify_order(terminal, post.attach, {
                    "out_trade_no": order.order_sn,
                    "order_amount": order.paid_amount,
                    "description": description,
                    "redirect_url": post.redirect_url
                }, qr=True)
        except Exception as e:
            raise AppException(str(e))
